package com.example.demo.controller;

import com.example.demo.component.OnlineUserManger;
import com.example.demo.model.Friend;
import com.example.demo.model.Message;
import com.example.demo.model.User;
import com.example.demo.myBatisMapper.MessageMapper;
import com.example.demo.myBatisMapper.MessageSessionMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.List;

@Component
public class WebSocketController extends TextWebSocketHandler {
    @Autowired
    private OnlineUserManger onlineUserManger;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private MessageSessionMapper messageSessionMapper;

    @Autowired
    private MessageMapper messageMapper;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        //这个方法会在WebSocket连接建立成功后,被自动调用
        System.out.println("TestWebSocketController 连接成功!");
        User user = (User) session.getAttributes().get("user");
        if (user == null){
            return;
        }
        //把这个键值对给存起来
        onlineUserManger.online(user.getUserId(), session);
        System.out.println("用户"+user.getUsername()+"上线!");
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        //这个方法是在WebSocket收到消息的时候,被自动调用
        System.out.println("TestWebSocketController 收到消息!" + message.toString());
        //1.先获取到当前用户的信息
        User user = (User) session.getAttributes().get("user");
        if (user == null){
            System.out.println("WebSocketController user == null");
            return;
        }
        //2.针对请求进行解析,把json格式的字符串转换为java中的对象
        MessageRequest req =  objectMapper.readValue(message.getPayload(),MessageRequest.class);
        if (req.getType().equals("message")){
            //进行消息转发
            transferMessage(user,req);
        }else {
            System.out.println("messageRequest type有误!" + message.getPayload());
        }
    }

    //通过这个方法来完成消息实际的转发工作
    private void transferMessage(User fromUser, MessageRequest req) throws IOException {
        //1.先构造一个待转发的响应对象,MessageResponse
        MessageResponse messageResponse = new MessageResponse();
        messageResponse.setType("message");
        messageResponse.setFromId(fromUser.getUserId());
        messageResponse.setFromName(fromUser.getUsername());
        messageResponse.setSessionId(req.getSessionId());
        messageResponse.setContent(req.getContent());
        //把java对象转换成json格式字符串
        String respJson = objectMapper.writeValueAsString(messageResponse);
        System.out.println("transferMessage respJson:" + respJson);
        //2.根据请求中的sessionId,获取这个MessageSession里都有哪些用户,通过查询数据库.
        List<Friend> friends = messageSessionMapper.getFriendsBySessionId(req.getSessionId(), fromUser.getUserId());
        //此处上述数据库查询会把当前发消息的用户刨除掉,而我们最终转发的时候也要把发送消息的人发一次
        //所以在list中把自己添加进去
        Friend myself = new Friend();
        myself.setFriendId(fromUser.getUserId());
        myself.setFriendName(fromUser.getUsername());
        friends.add(myself);
        //3.循环遍历上述列表,给列表中的每个用户都发一份响应消息
        // 知道了每个用户的userId,进一步查询刚才准备好的onlineUserManger,就知道了对应的webSocketSession
        //从而进行消息的转发
        //这里除了给查询到的好友们发,也要给自己发一个,方便实现在自己的客户都安上显示自己发送的信息
        //后端逻辑支持单聊也支持群聊
        for (Friend friend:friends) {
            WebSocketSession webSocketSession = onlineUserManger.getSession(friend.getFriendId());
            if (webSocketSession == null){
                //如果该用户不在线,就不发送
                continue;
            }else {
                webSocketSession.sendMessage(new TextMessage(respJson));
                System.out.println("消息已转发!");
            }
        }
        //4.转发的消息还要保存到数据库中,后续用户下线之后,重新上线,还可以通过历史消息的方式获取之前的消息.
        // 需要往message表里写入一条记录
        Message message = new Message();
        message.setFromId(fromUser.getUserId());
        message.setSessionId(req.getSessionId());
        message.setContent(req.getContent());
        //自增主键,时间字段可以通过sql在数据库中生成
        messageMapper.add(message);
    }


    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        //这个方法会在连接出现异常的时候,被自动调用
        System.out.println("TestWebSocketController 连接异常!" + exception.toString());
        User user = (User) session.getAttributes().get("user");
        if (user == null){
            return;
        }
        onlineUserManger.offline(user.getUserId(), session);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        //这个方法会在连接正常关闭之后,被自动调用
        System.out.println("TestWebSocketController 连接关闭!" + status.toString());
        User user = (User) session.getAttributes().get("user");
        if (user == null){
            return;
        }
        onlineUserManger.offline(user.getUserId(), session);
        System.out.println("用户"+user.getUsername()+"下线!");
    }
}
